<?php

namespace Project\Admin\Middleware;

use Closure;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Facades\JWTAuth;

class RefreshToken extends BaseMiddleware
{

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // 检查此次请求中是否带有 token，如果没有则抛出异常。
        $this->checkForToken($request);

        $auth = auth()->guard(config('admin.admin_guard'));
        
        // 使用 try 包裹，以捕捉 token 过期所抛出的 TokenExpiredException  异常
        try {
            // 检测用户的登录状态，如果正常则通过
            if ($auth->check()) {
                return $next($request);
            }
            throw new UnauthorizedHttpException('jwt-auth', '未登录或已超时');
        } catch (TokenExpiredException $exception) {
            // 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常，我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
            try {
                // 刷新用户的 token
                $token = $auth->refresh();

                // 使用一次性登录以保证此次请求的成功
                $auth->onceUsingId($this->auth->manager()
                    ->getPayloadFactory()
                    ->buildClaimsCollection()
                    ->toPlainArray()['sub']);

                $token = [
                    'access_token' => $token,
                    'token_type'   => 'bearer',
                    'expires_in'   => $auth->factory()->getTTL() * 60,
                ];
                return $next($request)->withHeaders([
                    'Access-Control-Expose-Headers' => 'AuthorKey',
                    'Authorization' => $token['token_type'] . ' ' . $token['access_token'],
                    'AuthorKey' => json_encode($token)
                ]);
            } catch (JWTException $exception) {
                // 如果捕获到此异常，即代表 refresh 也过期了，用户无法刷新令牌，需要重新登录。
                throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
            }
        }
    }
}
